package com.bluesky.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bluesky.common.Constants;
import com.bluesky.common.enums.DelFlagEnum;
import com.bluesky.common.enums.StatusEnum;
import com.bluesky.common.enums.YesNoEnum;
import com.bluesky.common.exception.CustomException;
import com.bluesky.common.utils.SecurityUtils;
import com.bluesky.system.common.dto.SysUserAddDTO;
import com.bluesky.system.common.dto.SysUserEditDTO;
import com.bluesky.system.common.dto.SysUserQueryDTO;
import com.bluesky.system.common.dto.SysUserResetPwdDTO;
import com.bluesky.system.entity.SysDept;
import com.bluesky.system.entity.SysUser;
import com.bluesky.system.entity.SysUserPost;
import com.bluesky.system.entity.SysUserRole;
import com.bluesky.system.mapper.SysUserMapper;
import com.bluesky.system.service.ISysDeptService;
import com.bluesky.system.service.ISysUserPostService;
import com.bluesky.system.service.ISysUserRoleService;
import com.bluesky.system.service.ISysUserService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Resource
    PasswordEncoder passwordEncoder;

    @Resource
    ISysUserRoleService sysUserRoleService;

    @Resource
    ISysUserPostService sysUserPostService;

    @Resource
    ISysDeptService sysDeptService;

    @Override
    public IPage<SysUser> page(Page reqPage, SysUserQueryDTO req) {
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getAccount()), SysUser::getAccount, req.getAccount());
        queryWrapper.like(StrUtil.isNotBlank(req.getNickname()), SysUser::getNickname, req.getNickname());
        queryWrapper.like(StrUtil.isNotBlank(req.getRealname()), SysUser::getRealname, req.getRealname());
        queryWrapper.like(StrUtil.isNotBlank(req.getEnglishName()), SysUser::getEnglishName, req.getEnglishName());
        queryWrapper.like(StrUtil.isNotBlank(req.getEmail()), SysUser::getEmail, req.getEmail());
        queryWrapper.like(StrUtil.isNotBlank(req.getPhone()), SysUser::getPhone, req.getPhone());
        queryWrapper.like(StrUtil.isNotBlank(req.getStaffNumber()), SysUser::getStaffNumber, req.getStaffNumber());
        queryWrapper.like(StrUtil.isNotBlank(req.getDeptId()), SysUser::getDeptId, req.getDeptId());
        queryWrapper.eq(SysUser::getStatus, StatusEnum.YES.getCode());
        queryWrapper.orderByAsc(SysUser::getCreatedTime);
        IPage<SysUser> page = this.page(reqPage, queryWrapper);
        page.getRecords().forEach(item -> {
            SysDept sysDept = sysDeptService.getById(item.getDeptId());
            if (Objects.nonNull(sysDept)) {
                item.setDeptName(sysDept.getDeptName());
            }

            List<SysUserRole> sysUserRoleList = sysUserRoleService.list(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, item.getId()));
            item.setRoleIds(sysUserRoleList.stream().map(item2 -> item2.getRoleId().toString()).collect(Collectors.toList()));

            List<SysUserPost> sysUserPostList = sysUserPostService.list(Wrappers.lambdaQuery(SysUserPost.class).eq(SysUserPost::getUserId, item.getId()));
            item.setPostIds(sysUserPostList.stream().map(item2 -> item2.getPostId().toString()).collect(Collectors.toList()));
        });
        return page;
    }

    @Override
    public List<SysUser> list(SysUserQueryDTO req) {
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getAccount()), SysUser::getAccount, req.getAccount());
        queryWrapper.like(StrUtil.isNotBlank(req.getNickname()), SysUser::getNickname, req.getNickname());
        queryWrapper.like(StrUtil.isNotBlank(req.getRealname()), SysUser::getRealname, req.getRealname());
        queryWrapper.like(StrUtil.isNotBlank(req.getEnglishName()), SysUser::getEnglishName, req.getEnglishName());
        queryWrapper.like(StrUtil.isNotBlank(req.getEmail()), SysUser::getEmail, req.getEmail());
        queryWrapper.like(StrUtil.isNotBlank(req.getPhone()), SysUser::getPhone, req.getPhone());
        queryWrapper.like(StrUtil.isNotBlank(req.getStaffNumber()), SysUser::getStaffNumber, req.getStaffNumber());
        queryWrapper.like(StrUtil.isNotBlank(req.getDeptId()), SysUser::getDeptId, req.getDeptId());
        queryWrapper.eq(SysUser::getStatus, StatusEnum.YES.getCode());
        queryWrapper.orderByAsc(SysUser::getCreatedTime);
        List<SysUser> list = this.list(queryWrapper);
        list.forEach(item -> {
            SysDept sysDept = sysDeptService.getById(item.getDeptId());
            if (Objects.nonNull(sysDept)) {
                item.setDeptName(sysDept.getDeptName());
            }
        });
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysUserAddDTO req) {
        if (!this.checkUniqueAccount(req.getAccount(), null)) {
            throw new CustomException("账号已存在");
        }
        if (!this.checkUniqueEmail(req.getEmail(), null)) {
            throw new CustomException("邮箱已存在");
        }
        if (!this.checkUniquePhone(req.getPhone(), null)) {
            throw new CustomException("手机号已存在");
        }
        if (!this.checkUniqueStaffNumber(req.getStaffNumber(), null)) {
            throw new CustomException("工号已存在");
        }
        SysUser entity = BeanUtil.copyProperties(req, SysUser.class);
        // 密码加密
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        entity.setPswModified(YesNoEnum.NO.getCode());
        this.save(entity);

        // 删除用户与岗位关联
        sysUserPostService.remove(Wrappers.lambdaQuery(SysUserPost.class).eq(SysUserPost::getUserId, entity.getId()));
        // 新增用户与岗位关联
        if (Objects.nonNull(req.getPostIds())) {
            List<SysUserPost> sysUserPostList = req.getPostIds().stream().map(item -> {
                SysUserPost sysUserPost = new SysUserPost();
                sysUserPost.setUserId(entity.getId());
                sysUserPost.setPostId(item);
                return sysUserPost;
            }).collect(Collectors.toList());
            sysUserPostService.saveBatch(sysUserPostList);
        }

        // 删除用户与角色关联
        sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, entity.getId()));
        // 新增用户与角色关联
        if (Objects.nonNull(req.getRoleIds())) {
            List<SysUserRole> sysUserRoleList = req.getRoleIds().stream().map(item -> {
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setUserId(entity.getId());
                sysUserRole.setRoleId(item);
                return sysUserRole;
            }).collect(Collectors.toList());
            sysUserRoleService.saveBatch(sysUserRoleList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysUserEditDTO req) {
        if (!this.checkUniqueAccount(req.getAccount(), req.getId())) {
            throw new CustomException("账号已存在");
        }
        if (!this.checkUniqueEmail(req.getEmail(), req.getId())) {
            throw new CustomException("邮箱已存在");
        }
        if (!this.checkUniquePhone(req.getPhone(), req.getId())) {
            throw new CustomException("手机号已存在");
        }
        if (!this.checkUniqueStaffNumber(req.getStaffNumber(), req.getId())) {
            throw new CustomException("工号已存在");
        }
        SysUser sysUser = this.getById(req.getId());
        if (!SecurityUtils.getSysUser().getAccount().equals(Constants.SUPER_ADMIN_ACCOUNT) && sysUser.getAccount().equals(Constants.SUPER_ADMIN_ACCOUNT)) {
            throw new CustomException(String.format("账号【%s】不允许修改", sysUser.getRealname()));
        }
        SysUser entity = BeanUtil.copyProperties(req, SysUser.class);
        this.updateById(entity);
        // 删除用户与岗位关联
        sysUserPostService.remove(Wrappers.lambdaQuery(SysUserPost.class).eq(SysUserPost::getUserId, entity.getId()));
        // 新增用户与岗位关联
        if (Objects.nonNull(req.getPostIds())) {
            List<SysUserPost> sysUserPostList = req.getPostIds().stream().map(item -> {
                SysUserPost sysUserPost = new SysUserPost();
                sysUserPost.setUserId(entity.getId());
                sysUserPost.setPostId(item);
                return sysUserPost;
            }).collect(Collectors.toList());
            sysUserPostService.saveBatch(sysUserPostList);
        }

        // 删除用户与角色关联
        sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, entity.getId()));
        // 新增用户与角色关联
        if (Objects.nonNull(req.getRoleIds())) {
            List<SysUserRole> sysUserRoleList = req.getRoleIds().stream().map(item -> {
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setUserId(entity.getId());
                sysUserRole.setRoleId(item);
                return sysUserRole;
            }).collect(Collectors.toList());
            sysUserRoleService.saveBatch(sysUserRoleList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        idList.forEach(item -> {
            SysUser sysUser = this.getById(item);
            if (sysUser.getAccount().equals(Constants.SUPER_ADMIN_ACCOUNT)) {
                throw new CustomException(String.format("账号【%s】不允许删除", sysUser.getRealname()));
            }
            this.update(Wrappers.lambdaUpdate(SysUser.class).eq(SysUser::getId, item).set(SysUser::getDelFlag, DelFlagEnum.YES.getCode()));
        });
        // this.removeByIds(Arrays.asList(ids.split(",")));
    }

    @Override
    public SysUser view(String id) {
        return this.getById(id);
    }

    @Override
    public void resetPwd(SysUserResetPwdDTO req) {
        SysUser entity = BeanUtil.copyProperties(req, SysUser.class);
        // 密码加密
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        entity.setPswModified(YesNoEnum.YES.getCode());
        this.updateById(entity);
    }

    private Boolean checkUniqueAccount(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysUser entity = getOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getAccount)
                .eq(SysUser::getAccount, value).last("limit 1"));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueEmail(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysUser entity = getOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getEmail)
                .eq(SysUser::getEmail, value).last("limit 1"));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniquePhone(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysUser entity = getOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getPhone)
                .eq(SysUser::getPhone, value).last("limit 1"));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueStaffNumber(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysUser entity = getOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getStaffNumber)
                .eq(SysUser::getStaffNumber, value).last("limit 1"));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
